﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Xml.Serialization;
using System.IO;
using System.Reflection;
using System.Xml;
using ElisaHippo.Properties;

namespace ElisaHippo
{
    /// <summary>
    /// Interaction logic for Page2.xaml
    /// </summary>
    public partial class MannualInput : Window
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        ObservableCollection<Recipe> recipes = new ObservableCollection<Recipe>();
        ExperimentGroups groupsInfo = new ExperimentGroups();
        Dictionary<string, List<string>> group_tests = new Dictionary<string, List<string>>();
        int gridStartPos = 1;
        int sampleCount = 16;
        bool bok = false;

        public ObservableCollection<Recipe> Recipes { 
            get
            {
                return recipes;
            }
            set
            {
                recipes = value;
            }
        }

        public ExperimentGroups GroupsInfo
        {
            set
            {
                groupsInfo = value;
            }
        }

        public void RegisterGroupsForRecipe()
        {
            foreach (Recipe r in recipes)
                r.AllGroups = groupsInfo;
        }
        public MannualInput()
        {
            InitializeComponent();
            ReadSumUpGroups();
            btnNext.IsEnabled = false;
            log.InfoFormat("Version is： {0}",stringRes.version);
            txtSampleCount.Text = sampleCount.ToString();
            txtStartGrid.Text = gridStartPos.ToString();
            this.SizeToContent = System.Windows.SizeToContent.Height;
            this.Loaded += new RoutedEventHandler(PageMannualInput_Loaded);
        }


        private void ReadSumUpGroups()
        {
            //throw new NotImplementedException();
            log.Info("Read Groups sum up from configure.");
            string s = Utility.GetDataFolder();
            string sSummarizeFolder = s + "GroupSumUp\\";
            IEnumerable<string> allFiles = Directory.EnumerateFiles(sSummarizeFolder, "*.txt");

            foreach (string sFile in allFiles)
            {
                using (StreamReader sr = new StreamReader(sFile))
                {
                    string sTest = "";
                    List<string> tests = new List<string>();
                    int slashIndex = sFile.LastIndexOf("\\");
                    string shortName = sFile.Substring(slashIndex + 1);
                    shortName = shortName.Substring(0, shortName.Length - 4);
                    Debug.WriteLine(shortName);
                    while ((sTest = sr.ReadLine()) != null)
                    {
                        tests.Add(sTest);
                    }
                    group_tests.Add(shortName, tests);
                }
            }
            log.InfoFormat("There are {0} groups read.", group_tests.Count);
        }


        void dataGridView_SelectionChanged(object sender, EventArgs e)
        {
            if (lstTestGroup.SelectedIndex == -1)
            {
                SetInfo("必须先选择当日测试", Colors.Red);

            }
            foreach (DataGridViewCell cell in dataGridView.SelectedCells)
            {
                System.Windows.Media.Color color =  recipes[lstTestGroup.SelectedIndex].Color;
                cell.Style.BackColor = System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);
                cell.Value = recipes[lstTestGroup.SelectedIndex].Name;
            }
        }

        void PageMannualInput_Loaded(object sender, RoutedEventArgs e)
        {
            log.Info("Form loaded");
            recipes.Add(new Recipe(Colors.White, "无", new ObservableCollection<string>() ));
            lstTestGroup.DataContext = recipes;
            lstTestGroup.SelectedIndex = 0;
            UpdateDataGridView();
            dataGridView.SelectionChanged += new EventHandler(dataGridView_SelectionChanged);
            dataGridView.EditMode = DataGridViewEditMode.EditProgrammatically;
        }

        private void AddNull2Groups()
        {
            //ExperimentGroup doNothing =   new ExperimentGroup("无",  new ObservableCollection<string>());
            //if (groups.IndexOf(doNothing) == -1)
            //    groups.Add(doNothing);
        }

        private ObservableCollection<string> GetDetailed(string sGroupName)
        {
            return new ObservableCollection<string>();
        }
        private void btnStatistics_Click(object sender, RoutedEventArgs e)
        {
            log.Info("statistic the tests");
            bok = CheckSettings();
            if (!bok)
                return;
            else
            {
                SetInfo("", Colors.Green);
            }
            Dictionary<string, HashSet<string>> testsSampleIDs;
            List<string> barcodes;
            GetTestSampleIDDictionary( out testsSampleIDs, out barcodes);
            Statistics statisticsForm = new Statistics(testsSampleIDs);
            statisticsForm.ShowDialog();
            btnNext.IsEnabled = true;
            

        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            log.Info("button next clicked");
            bok = CheckSettings();
            if (!bok)
                return;
            
            try
            {

                Utility.SaveSetting(dataGridView, sampleCount);
            }
            catch (Exception ex)
            {
                SetInfo("保存Excel文件时遇到错误： " + ex.Message, Colors.Red);
                return;
            }

            try
            {
                GenerateJobList();
            }
            catch(Exception ex)
            {
                SetInfo("生成Joblist失败： " + ex.Message,Colors.Red);
                return;
            }
            bok = true;
            this.Close();
        }

        private bool CheckSettings()
        {
            int count = 0;
            bool sequent = true;
            int colNum = (int)Math.Ceiling(sampleCount / 16.0);
            List<int> rowCounts = new List<int>();
            for (int i = 0; i < colNum - 1; i++)
                rowCounts.Add(16);
            if (sampleCount % 16 == 0)
                rowCounts.Add(16);
            else
                rowCounts.Add(sampleCount % 16);


            for (int c = 0; c < colNum; c++)
            {
                for (int r = 0; r < rowCounts[c]; r++)
                {
                    if (dataGridView.Rows[r].Cells[c].Value.ToString() != "")
                    {
                        count++;
                    }
                    else
                    {
                        if (count < sampleCount)
                            sequent = false;
                    }
                }
            }

            if (!sequent)
            {
                SetInfo("样品没有全部设置", Colors.Red);
                return false;
            }

            if (count != sampleCount)
            {
                SetInfo(string.Format("样品总数为：{0}，有{1}个已被设置,请确保二者相等。", sampleCount, count), Colors.Red);
                return false;
            }

            return true;

        }

        private void GenerateJobList()
        {
            log.Info("Generate job list.");
            Dictionary<string, HashSet<string>> testsSampleIDs;
            List<string> barcodes;
            bool bHaveWork2Do =  GetTestSampleIDDictionary( out testsSampleIDs, out barcodes);
            if (!bHaveWork2Do)
            {
                throw new Exception("样品不需要做任何测试！");
            }

            #region write barcodes
            int startIndex = (gridStartPos - 1) * 16;
            int endIndex = startIndex + sampleCount -1;
            StreamWriter swBarcodes = CreateBarcodesFile();
            int nCurIndex = 0;
            int realBarcodesIndex = 0;
            for (int c = 0; c < 12; c++)
            {
                swBarcodes.WriteLine(string.Format("[Grid{0}]", c+1));
                for (int r = 0; r < 16; r++)
                {
                    //swBarcodes.WriteLine(string.Format("{0}  =  {1}", r + 1, sBarcode));
                    string sBarcode = "$$$";
                    if (nCurIndex <= endIndex && nCurIndex >= startIndex)
                    {
                        sBarcode = barcodes[realBarcodesIndex++];
                        
                    }
                    string s2Write = string.Format("{0} = {1}", r + 1, sBarcode);
                    swBarcodes.WriteLine(s2Write);
                    nCurIndex++;
                }
            }
            swBarcodes.Close();
            #endregion
          
            #region check constrain
            string errMsg;
            bool bok = CheckConstrain(testsSampleIDs,out errMsg);
            if (!bok)
                throw new Exception(errMsg);
            #endregion

            SummarizeForEachGroup2(testsSampleIDs);

            //3 为每个测试创建文件
            Utility.CreateTestFiles(testsSampleIDs);
        }

        private bool GetTestSampleIDDictionary(out Dictionary<string, HashSet<string>> testsSampleIDs,out List<string> barcodes , bool is62Radix = true)
        {
            //1 create dictionary Recipe-recipe选中的所有测试名
            Dictionary<string, HashSet<string>> allRecipesTests = new Dictionary<string, HashSet<string>>();
            HashSet<string> allTests = new HashSet<string>();
            foreach (Recipe recipe in recipes)
            {
                HashSet<string> thisRecipeTests = new HashSet<string>();
                foreach (string sGroupName in recipe.SelectedGroups)
                {
                    ExperimentGroup selGroup = (from g in groupsInfo where g.Name == sGroupName select g).First();
                    foreach (Test t in selGroup.AllowedTests)
                    {
                        if (t.IsSelected)
                        {
                            thisRecipeTests.Add(t.Name);
                            allTests.Add(t.Name);
                        }
                    }
                }
                allRecipesTests.Add(recipe.Name, thisRecipeTests);
            }

            //2 create dictionary test-需要做该test的所有sampleID
            testsSampleIDs = new Dictionary<string, HashSet<string>>();
            foreach (string s in allTests)
            {
                testsSampleIDs.Add(s, new HashSet<string>());
            }


            int colNum = (int)Math.Ceiling(sampleCount / 16.0);
            List<int> rowCounts = new List<int>();
            for (int i = 0; i < colNum - 1; i++)
                rowCounts.Add(16);

            if (sampleCount % 16 == 0)
                rowCounts.Add(16);
            else
                rowCounts.Add(sampleCount % 16);


            #region get tests
            bool bHaveWork2Do = false;
            string sData = DateTime.Now.ToString("yyMMddHHmmss");
            string s62Barcode = AnyRadixConvert.h2x(long.Parse(sData), 62);
            if (!is62Radix)
                s62Barcode = "";
            barcodes = new List<string>();
            for (int c = 0; c < colNum; c++)
            {

                for (int r = 0; r < rowCounts[c]; r++)
                {
                    string sBarcode = string.Format("{0}{1:D2}{2:D2}", s62Barcode, c + gridStartPos, r + 1);
                    barcodes.Add(sBarcode);
                    string sRecipe = dataGridView.Rows[r].Cells[c].Value.ToString();
                    HashSet<string> testsForTheRecipe = allRecipesTests[sRecipe];
                    if (testsForTheRecipe.Count > 0)
                        bHaveWork2Do = true;
                    foreach (string sTest in testsForTheRecipe)
                    {
                        testsSampleIDs[sTest].Add(sBarcode);
                    }
                }
            }
         
            #endregion

            return bHaveWork2Do;
        }

        private bool CheckConstrain(Dictionary<string, HashSet<string>> testsSampleIDs,out string errMsg)
        {
            bool bok = true;
            errMsg = "";
            //throw new NotImplementedException();
            List<string> tests2Constrain = new List<string>();
            string sConstrainFile = Utility.GetDataFolder() + stringRes.groupFolder + stringRes.constrainTestsConfigFile;
            
            using (StreamReader sr = new StreamReader(sConstrainFile))
            {
                string s = "";
                while ((s = sr.ReadLine()) != null)
                {
                    tests2Constrain.Add(s);
                }
            }

            foreach (string test2Constrain in tests2Constrain)
            {
                int count = testsSampleIDs[test2Constrain].Count;
                if ( count> 88)
                {
                    errMsg = string.Format("测试：{0}的数量为{1},注意不得大于88！", test2Constrain, count);
                    return false;
                }
            }
            return bok;
        }

        private void SummarizeForEachGroup(Dictionary<string, HashSet<string>> testsSampleIDs)
        {
            string sFolder = stringRes.EvoProcessFolder + stringRes.selectionFolder;

            if (!Directory.Exists(sFolder))
                Directory.CreateDirectory(sFolder);

            string sFile = sFolder + "Selection_var.csv";//"Selection\\var.csv";
            StreamWriter sw = new StreamWriter(sFile);
            foreach (string sGroup in group_tests.Keys) //test for all groups
            {
                bool bFound = false;
                foreach (string sTest in group_tests[sGroup]) //check for all tests in the group, see whether there is a test to go
                {
                    if (testsSampleIDs[sTest].Count > 0)
                    {
                        bFound = true;
                        break;
                    }
                }
                int res = bFound ? 1 : 0;
                sw.WriteLine(string.Format("{0};0;{1}", sGroup, res));
            }
            sw.Close();
        }


        private void SummarizeForEachGroup2(Dictionary<string, HashSet<string>> testsSampleIDs)
        {
            foreach (string sGroup in group_tests.Keys) //test for all groups
            {
                string sFile = Utility.GetSaveFolder() + "\\" + sGroup + ".txt";
                using (StreamWriter sw = new StreamWriter(sFile))
                {
                    bool bFound = false;
                    foreach (string sTest in group_tests[sGroup]) //check for all tests in the group, see whether there is a test to go
                    {
                        if (testsSampleIDs[sTest].Count > 0)
                        {
                            bFound = true;
                            break;
                        }
                    }
                    sw.WriteLine((bFound ? 1 : 0).ToString());
                }
            }
        }

        private StreamWriter CreateBarcodesFile()
        {
            string sFile = Utility.GetSaveFolder() + "\\barcodes.txt";
            return new StreamWriter(sFile);

        }

        private void UpdateDataGridView()
        {
            //dataGridView.Columns.Add(new System.Windows.Forms.DataGridViewColumn());
            dataGridView.AllowUserToAddRows = false;
            dataGridView.Columns.Clear();
            List<string> strs = new List<string>();

            int colNum = (int)Math.Ceiling( sampleCount / 16.0);
            for (int j = 0; j < colNum; j++)
                strs.Add("");

            for (int i = 0; i < colNum; i++)
            {
                DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
                column.HeaderText = string.Format("条{0}", gridStartPos+i);
                dataGridView.Columns.Add(column);

                //dataGridView.Columns[i].HeaderCell.Value = string.Format("Grid{0}", i + 1);
            }

            dataGridView.RowHeadersWidth = 80;
            for (int i = 0; i < 16; i++)
            {
                dataGridView.Rows.Add(strs.ToArray());
                dataGridView.Rows[i].HeaderCell.Value = string.Format("行{0}", i + 1);
            }
        }

        private void txtStartGrid_TextChanged(object sender, TextChangedEventArgs e)
        {

        }


        void SetInfo(string s, Color color)
        {
            if (txtInfo == null)
                return;

            txtInfo.Background = new SolidColorBrush(Colors.White);
            txtInfo.Text = s;
            txtInfo.Foreground = new SolidColorBrush(color);
        }

        private void txtSampleCount_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private void btnSet_Click(object sender, RoutedEventArgs e)
        {
            int i = 0;
            bool bok = int.TryParse(txtStartGrid.Text, out i);
            if (!bok)
                SetInfo("Grid起始号必须为数字！", Colors.Red);
            if (i < 1 || i > 30)
            {
                bok = false;
                SetInfo("Grid起始位置必须位于1到30之间", Colors.Red);
            }
            if (!bok)
            {
                txtStartGrid.Text = gridStartPos.ToString();
                return;
            }
            gridStartPos = i;

            bok = int.TryParse(txtSampleCount.Text, out i);
            if (!bok)
                SetInfo("样品数量必须为数字！", Colors.Red);
            if (i <= 0 || i > 192)
            {
                SetInfo("样品数量必须介于0和192之间", Colors.Red);
                bok = false;
            }

            if (!bok)
            {
                txtSampleCount.Text = sampleCount.ToString();
                return;
            }
            sampleCount = i;

            UpdateDataGridView();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            Utility.WriteExecuteResult(bok);
        }

     
        private void CommandHelp_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Help help = new Help();
            help.ShowDialog();
        }

        private void CommandHelp_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

 
    }


    public class AnyRadixConvert
    {
        private static char[] rDigits = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 
        'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
        'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't' ,'u', 'v', 'w', 'x',
        'y', 'z'};

        /// <summary>
        /// 将指定基数的数字的 System.String 表示形式转换为等效的 64 位有符号整数。
        /// </summary>
        /// <param name="value">包含数字的 System.String。</param>
        /// <param name="fromBase">value 中数字的基数，它必须是[2,36]</param>
        /// <returns>等效于 value 中的数字的 64 位有符号整数。- 或 - 如果 value 为 null，则为零。</returns>
        private long x2h(string value, int fromBase)
        {
            value = value.Trim();
            if (string.IsNullOrEmpty(value))
            {
                return 0L;
            }

            string sDigits = new string(rDigits, 0, fromBase);
            long result = 0;
            //value = reverse(value).ToUpper(); 1
            value = value.ToUpper();// 2
            for (int i = 0; i < value.Length; i++)
            {
                if (!sDigits.Contains(value[i].ToString()))
                {
                    throw new ArgumentException(string.Format("The argument \"{0}\" is not in {1} system.", value[i], fromBase));
                }
                else
                {
                    try
                    {
                        //result += (long)Math.Pow(fromBase, i) * getcharindex(rDigits, value[i]); 1
                        result += (long)Math.Pow(fromBase, i) * getcharindex(rDigits, value[value.Length - i - 1]);//   2
                    }
                    catch
                    {
                        throw new OverflowException("运算溢出.");
                    }
                }
            }

            return result;
        }

        private int getcharindex(char[] arr, char value)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] == value)
                {
                    return i;
                }
            }
            return 0;
        }

        //long转化为toBase进制
        public static string h2x(long value, int toBase)
        {
            int digitIndex = 0;
            long longPositive = Math.Abs(value);
            int radix = toBase;
            char[] outDigits = new char[63];

            for (digitIndex = 0; digitIndex <= 64; digitIndex++)
            {
                if (longPositive == 0) { break; }

                outDigits[outDigits.Length - digitIndex - 1] =
                    rDigits[longPositive % radix];
                longPositive /= radix;
            }
            return new string(outDigits, outDigits.Length - digitIndex, digitIndex);
        }

        //任意进制转换,将fromBase进制表示的value转换为toBase进制
        public string X2X(string value, int fromBase, int toBase)
        {
            if (string.IsNullOrEmpty(value.Trim()))
            {
                return string.Empty;
            }

            if (fromBase < 2 || fromBase > 36)
            {
                throw new ArgumentException(String.Format("The fromBase radix \"{0}\" is not in the range 2..36.", fromBase));
            }

            if (toBase < 2 || toBase > 36)
            {
                throw new ArgumentException(String.Format("The toBase radix \"{0}\" is not in the range 2..36.", toBase));
            }

            long m = x2h(value, fromBase);
            string r = h2x(m, toBase);
            return r;
        }
    }

}
